package com.codemate.interview.filter.bloom;

import cn.hutool.bloomfilter.BloomFilter;
import java.util.LinkedList;

/**
 * BloomFilter 实现
 * <br> 1.构建hash算法
 * <br> 2.散列hash映射到数组的bit位置
 * <br> 3.验证
 * <br> 此实现方式可以指定Hash算法
 *
 * @author hice
 */
public class LruBitMapBloomFilter implements MetaBloomFilter {

    private static final long serialVersionUID = 1L;

    private MetaBloomFilter[] filters;

    /**
     * LRU存储量限制
     */
    private final long lruSize;

    /**
     * LRU存储数据链表
     */
    private final LinkedList<String> lruList = new LinkedList<>();

    /**
     * 构造
     *
     * @param m M值决定BitMap的大小
     */
    public LruBitMapBloomFilter(int m) {
        lruSize = m;
        long size = (long) m * 1024 * 1024 * 8;
        filters = new MetaBloomFilter[]{
            new DefaultBloomFilter(size),
        };
    }

    /**
     * 使用自定的多个过滤器建立BloomFilter
     *
     * @param m       M值决定BitMap的大小
     * @param filters Bloom过滤器列表
     */
    public LruBitMapBloomFilter(int m, MetaBloomFilter... filters) {
        this(m);
        this.filters = filters;
    }

    /**
     * 增加字符串到Filter映射中
     *
     * @param str 字符串
     */
    @Override
    public boolean add(String str) {
        if (lruList.size() >= lruSize) {
            remove(lruList.poll());
        }

        boolean flag = false;
        for (BloomFilter filter : filters) {
            flag |= filter.add(str);
        }

        if (flag) {
            lruList.add(str);
        }
        return flag;
    }

    /**
     * 是否可能包含此字符串，此处存在误判
     *
     * @param str 字符串
     * @return 是否存在
     */
    @Override
    public boolean contains(String str) {
        for (BloomFilter filter : filters) {
            if (!filter.contains(str)) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean remove(String str) {
        boolean flag = false;
        for (MetaBloomFilter filter : filters) {
            flag |= filter.remove(str);
        }
        return flag;
    }

}
